module es {
    /**
     * 使用案例
     * https://blog.csdn.net/qq_39162566/article/details/125105592
     */
    export class TimelineSprite extends Laya.Sprite {
        protected interval: number;
        protected tm: number;
        protected play_begin_pos: number;
        protected play_end_pos: number;
        protected loop: boolean = false;
        protected index: number = 0;
        protected frames: string[] = [];
        protected frameEvent: { [frameID: number]: Laya.Handler[] } = {};
        protected last_frame: Laya.Texture;

        /**
         * 最后一帧派发
         */
        public static readonly EVENT_ENDFRAME = "EVENT_ENDFRAME";
        /**
         * 非循环播放结束时触发
         */
        public static readonly EVENT_ENDED = "EVENT_ENDED";

        /**
         * 构造方法
         * @param frames 动画帧数组
         * @param frameRate 帧率 例如: frameRate = 30 那每帧的间隔就是33.33ms ( 1000 / 30 )
         */
        constructor(frames: string[], frameRate: number = 30) {
            super();
            this.frames = frames;
            this.interval = Math.floor(1000.0 * 1000 / frameRate) / 1000;
            this.tm = 0;
        }

        /**
         * 设置新的动画组
         * @param frames 动画帧数组
         * @param frameRate 帧率 可以不填 采用上一个动画的方案 默认30帧每秒
         */
        setNewAnimationFrames(frames: string[], frameRate?: number) {
            if (frameRate)
                this.interval = Math.floor(1000.0 * 1000 / frameRate) / 1000;
            this.frames = frames;
        }

        /**
         * 播放
         * @param loop 是否循环播放  默认false
         * @param start 开始播放的位置 百分百 0~1  循环中也是以这个为主
         * @param end 结束播放的位置 百分比 0～1
         */
        play(loop: boolean = false, start: number = 0, end: number = 1.0) {
            this.tm = 0;
            this.loop = loop;
            this.play_begin_pos = Math.floor(start * this.frames.length);
            this.play_end_pos = Math.floor(end * this.frames.length);
            this.index = this.play_begin_pos;
            this.last_frame = Laya.loader.getRes(this.frames[this.index]);
            this.add2aniPool();
        }


        /**
         * 添加一个事件
         * @param pos 位置 百分比 0～1
         * @param caller 
         * @param fun 
         * @param once 是否执行一次后自动移除
         */
        addEvent(pos: number, caller: any, fun: Function, once: boolean = false) {
            let frameIndex = Math.floor(pos * this.frames.length);
            let handlers = this.frameEvent[frameIndex];

            if (handlers && handlers.find(handler => {
                return handler.caller == caller && handler.method == fun;
            }) != null) {
                return;
            }
            handlers = this.frameEvent[frameIndex] || [];
            handlers.push(Laya.Handler.create(caller, fun, null, once));
            this.frameEvent[frameIndex] = handlers;
        }

        /**
         * 停止播放
         * 会停留在当前帧
         * 你可以使用 visible = false; 来隐藏 动画展示
         */
        stop() {
            this.removeFromPool();
        }

        /**
         * 
         * 更新帧
         */
        protected updateFrame(): void {
            this.onframeEvent();
            ++this.index;
            if (this.index >= this.play_end_pos) {
                this.event(TimelineSprite.EVENT_ENDFRAME);
                if (!this.loop) {
                    this.removeFromPool();
                    this.event(TimelineSprite.EVENT_ENDED);
                    return;
                }
                else {
                    this.index = this.play_begin_pos;
                }
            }
            this.last_frame = Laya.loader.getRes(this.frames[this.index]);
            this.draw();
        }

        protected onframeEvent() {
            const events = this.frameEvent[this.index];
            if (events) {
                for (let i = 0; i < events.length; i++) {
                    events[i].run();
                    if (events[i].once) {
                        events.splice(i--, 1);
                    }
                }
            }
        }

        private draw() {
            this.graphics.clear();
            this.graphics.drawImage(this.last_frame);
        }

        protected add2aniPool() {
            !TimelineFactory['instance'] && TimelineFactory['genSingleton']();
            TimelineFactory['instance'].appendTimeline(this);
        }

        protected removeFromPool() {
            TimelineFactory['instance'] && TimelineFactory['instance'].removeTimeline(this);
        }

        public clone() {
            let obj = new TimelineSprite(this.frames);
            for (let k in this) {
                if (typeof k == "number" || typeof k == "boolean") {
                    obj[k] = this[k];
                }
            }
            return obj;
        }
    }
}